/**
 * 
 */
package com.ld.tamp.web.support;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ld.base.support.PropertyHolder;
import com.ld.tamp.web.constant.WeiXinConstant;
import com.ld.tamp.web.dao.AuthorizerInfoDao;
import com.ld.tamp.web.dao.AuthorizerJsTicketDao;
import com.ld.tamp.web.dao.ComponentAccessTokenDao;

import weixin.popular.api.ComponentAPI;
import weixin.popular.bean.component.AuthorizerAccessToken;

/**
 * 
 * 公众号授权access_token管理器
 * @author KeYang
 *
 */
public class AuthorizerAccessTokenManager {

	private static final Logger logger = LoggerFactory.getLogger(AuthorizerAccessTokenManager.class);

	private static ScheduledExecutorService scheduledExecutorService;

	private static Map<String, ScheduledFuture<?>> futureMap = new HashMap<String, ScheduledFuture<?>>();

	private static int poolSize = 2;

	private static boolean daemon = Boolean.TRUE;
	
	private static String component_appid = PropertyHolder.getProperty(WeiXinConstant.COMPONENT_APPID);

	private static void initScheduledExecutorService() {
		scheduledExecutorService = Executors.newScheduledThreadPool(poolSize, new ThreadFactory() {

			@Override
			public Thread newThread(Runnable r) {
				Thread thread = Executors.defaultThreadFactory().newThread(r);
				thread.setDaemon(daemon);
				return thread;
			}
		});
	}

	public static void setPoolSize(int poolSize) {
		AuthorizerAccessTokenManager.poolSize = poolSize;
	}

	/**
	 * 设置线程方式
	 * 
	 * @param daemon
	 *            daemon
	 */
	public static void setDaemon(boolean daemon) {
		AuthorizerAccessTokenManager.daemon = daemon;
	}

	/**
	 * 初始化token 刷新，每118分钟刷新一次。
	 * 
	 * @param componentVerifyTicketService
	 * @param componentAccessTokenDao
	 * 
	 * @param appid
	 *            appid
	 * @param secret
	 *            secret
	 */
	public static void init(final String authorizer_appid, final String authorizer_refresh_token,
			final int initialDelay, ComponentAccessTokenDao componentAccessTokenDao,
			AuthorizerInfoDao authorizerInfoDao, AuthorizerJsTicketDao authorizerJsTicketDao) {

		if (scheduledExecutorService == null) {
			initScheduledExecutorService();
		}
		//防止重复启动
		if (futureMap.containsKey(authorizer_appid)) {
			futureMap.get(authorizer_appid).cancel(true);
		}
		ScheduledFuture<?> scheduledFuture = scheduledExecutorService.scheduleWithFixedDelay(new Runnable() {
			@Override
			public void run() {
				try {
					logger.info("刷新获取authorizer_access_token authorizer_appid:{}",authorizer_appid);
					AuthorizerAccessToken authorizerAccessToken = ComponentAPI.api_authorizer_token(componentAccessTokenDao.read().getComponentAccessToken(),
							component_appid, authorizer_appid, authorizer_refresh_token);
					if (authorizerAccessToken.isSuccess()) {
						authorizerInfoDao.update(authorizer_appid, authorizerAccessToken);
						logger.info("AUTHORIZER_ACCESS_TOKEN 刷新 成功  component_appid:{},authorizer_appid:{}", component_appid,authorizer_appid);
						//刷新成功后，刷新ticket
						AuthorizerJsTicketManager.init(authorizer_appid, 0, authorizerInfoDao, authorizerJsTicketDao);
						
					} else {
						throw new RuntimeException("AUTHORIZER_ACCESS_TOKEN刷新失败, "+authorizerAccessToken.getErrmsg());
					}
				} catch (Exception e) {
					logger.error("AUTHORIZER_ACCESS_TOKEN 刷新 失败  component_appid:{},authorizer_appid:{}", component_appid,authorizer_appid);
					e.printStackTrace();
				}
			}
		}, initialDelay, 118, TimeUnit.MINUTES);
		futureMap.put(authorizer_appid, scheduledFuture);
	}

	/**
	 * 取消 token 刷新
	 */
	public static void destroyed() {
		scheduledExecutorService.shutdownNow();
		logger.info("destroyed");
	}

	/**
	 * 取消刷新
	 * 
	 * @param appid
	 *            appid
	 */
	public static void destroyed(String appid) {
		if (futureMap.containsKey(appid)) {
			futureMap.get(appid).cancel(true);
			logger.info("destroyed appid:{}", appid);
		}
	}
}
